#pragma once

#include "libxml/parser.h"
#include "libxml/xpath.h"

#include <vector>
#include <string>
using namespace std;

class lightxquery
{
	xmlDocPtr _doc;
	xmlXPathContextPtr _ctx;
	const xmlChar *my_bad_cast(const char *s)
	{
		return reinterpret_cast<const xmlChar *>(s);
	}

	const char *xml_cast(const xmlChar *s)
	{
		return reinterpret_cast<const char *>(s);
	}
	public:
	lightxquery() : _doc(0), _ctx(0) { xmlInitParser(); }
	~lightxquery() 
	{
		if (_ctx) {
			xmlXPathFreeContext(_ctx);
			_ctx = 0;
		}
		if (_doc)
			xmlFreeDoc(_doc);
		
		xmlCleanupParser();
	}
	bool load(const string &file)
	{
		_doc = xmlReadFile(file.c_str(), "utf-8", XML_PARSE_NOBLANKS);
		if (!_doc)
			return false;
		_ctx = xmlXPathNewContext(_doc);
		if (!_ctx)
			return false;
		return true;
	}
	int how_many(const string &xpath)
	{
		xmlXPathObjectPtr obj = xmlXPathEvalExpression(my_bad_cast(xpath.c_str()), _ctx);
		int ret = obj ? obj->nodesetval->nodeNr : 0;
		if (obj)
			xmlXPathFreeObject(obj);
		return ret;
	}
	int get_attr_value(const string &xpath, const string &attr, unsigned int &value)
	{
		string v;
		int ret = get_attr_value(xpath, attr, v);
		if (ret != 0)
			return ret;
		if (v.size() == 0)
			return -1;
		sscanf(v.c_str(), "%d", &value);
		return 0;
	}
	int get_attr_value(const string &xpath, const string &attr, int &value)
	{
		string v;
		int ret = get_attr_value(xpath, attr, v);
		if (ret != 0)
			return ret;
		if (v.size() == 0)
			return -1;
		sscanf(v.c_str(), "%d", &value);
		return 0;
	}	
	int get_attr_value(const string &xpath, const string &attr, long long &value)
	{
		string v;
		int ret = get_attr_value(xpath, attr, v);
		if (ret != 0)
			return ret;
		if (v.size() == 0)
			return -1;
		sscanf(v.c_str(), "%lld", &value);
		return 0;
	}
	int get_attr_value(const string &xpath, const string &attr, float &value)
	{
		string v;
		int ret = get_attr_value(xpath, attr, v);
		if (ret != 0)
			return ret;
		if (v.size() == 0)
			return -1;
		sscanf(v.c_str(), "%f", &value);
		return 0;
	}
	int get_attr_value(const string &xpath, const string &attr, string &value)
	{
		int ret = 0;
		xmlXPathObjectPtr obj = xmlXPathEvalExpression(my_bad_cast(xpath.c_str()), _ctx);
		if (!obj)
			return -1;
		if (!(obj->nodesetval)) 
			ret = -3;
		if (obj->nodesetval->nodeNr < 1)
			ret = -1;
		if (obj->nodesetval->nodeNr > 1)
			ret = -2;

		if (ret == 0) {
			const xmlChar *a = xmlGetProp(obj->nodesetval->nodeTab[0], my_bad_cast(attr.c_str()));
			if (!a) {
				ret = -3;
			} else {
				value = xml_cast(const_cast<xmlChar *>(a));
				free(const_cast<xmlChar *>(a));
			}
		}
		xmlXPathFreeObject(obj);
		return ret;
	}
};
